/***************************************************************************
 *            screen.c
 *
 *  Mon Aug 25 16:38:05 2008
 *  Copyright  2008  Tiago Falcão
 *  <tiago@tiagofalcao.com>
 ****************************************************************************/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
 */
#include "screen.h" 
#include <stdlib.h>


object3d sphere;		//Esfera
object3d cube;			//Cubo
object3d teapot;		//Chaleira
object3d *selected=NULL;//Objeto selecionado

//Inicialização da Tela
void screen(int x,int y,int w,int h,char * title){
	//Double Buffer, RGBA e Depth
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	//Tamanho
	glutInitWindowSize (w, h);
	//Posição
	glutInitWindowPosition (x, y);
	//Cria Janela e seta Titulo
	glutCreateWindow (title);
    // Especifica que a cor de fundo da janela será preta
	glClearColor(0.0, 0.5, 0.5, 1.0);
	//Configura Iluminação
	setup_light();
	//Seta função de desenho
	glutDisplayFunc (display);
	//Inicializa Camera
	cam_init();
	//Seta função de redimensionamento
	glutReshapeFunc (reshape_listener);
	//Listener do Teclado
	glutKeyboardFunc(key_listener);
	glutSpecialFunc(special_key_listener);
	//Listener do Mouse
	glutMouseFunc(mouse_listener);
	//Listener do Scroll do Mouse
	glutMouseWheelFunc(mouse_wheel_listener);
	//Cria Menu
	create_menu();

	//Esfera
	sphere.selected=0;

	sphere.size=1.0;

	sphere.color.r=0.0;
	sphere.color.g=0.0;
	sphere.color.b=1.0;
	sphere.color.a=1.0;

	sphere.position.x=2.0;
	sphere.position.y=0.0;
	sphere.position.z=0.0;

	sphere.scale.x=1.0;
	sphere.scale.y=1.0;
	sphere.scale.z=1.0;

	sphere.rotate.x=0.0;
	sphere.rotate.y=0.0;
	sphere.rotate.z=0.0;

	sphere.ambient[0]=0.;
	sphere.ambient[1]=0.;
	sphere.ambient[2]=0.;
	sphere.ambient[3]=1.;
	sphere.diffuse[0]=0.1;
	sphere.diffuse[1]=0.5;
	sphere.diffuse[2]=0.8;
	sphere.diffuse[3]=1.;
	sphere.specular[0]=0.;
	sphere.specular[1]=0.;
	sphere.specular[2]=0.;
	sphere.specular[3]=1.;
	sphere.shininess=0.;
	sphere.emission[0]=0.;
	sphere.emission[1]=0.;
	sphere.emission[2]=0.;
	sphere.emission[3]=1.;

	sphere.display=simple_glutSolidSphere;
	sphere.display_selected=simple_glutWireSphere;


	//Cubo
	cube.selected=0;
	cube.size=1.0;
	cube.color.r=1.0;
	cube.color.g=0.0;
	cube.color.b=0.0;
	cube.color.a=1.0;
	cube.position.x=0.0;
	cube.position.y=0.0;
	cube.position.z=0.0;
	cube.scale.x=1.0;
	cube.scale.y=1.0;
	cube.scale.z=1.0;
	cube.rotate.x=0.0;
	cube.rotate.y=0.0;
	cube.rotate.z=0.0;

	cube.ambient[0]=0.;
	cube.ambient[1]=0.;
	cube.ambient[2]=0.;
	cube.ambient[3]=1.;
	cube.diffuse[0]=0.8;
	cube.diffuse[1]=0.8;
	cube.diffuse[2]=0.8;
	cube.diffuse[3]=1.;
	cube.specular[0]=1.;
	cube.specular[1]=1.;
	cube.specular[2]=1.;
	cube.specular[3]=1.;
	cube.shininess=3.;
	cube.emission[0]=0.;
	cube.emission[1]=0.;
	cube.emission[2]=0.;
	cube.emission[3]=1.;

	cube.display=glutSolidCube;
	cube.display_selected=glutWireCube;


	//Chaleira
	teapot.selected=0;
	teapot.size=0.5;
	teapot.color.r=0.0;
	teapot.color.g=1.0;
	teapot.color.b=0.0;
	teapot.color.a=0.2;
	teapot.position.x=-2.0;
	teapot.position.y=0.0;
	teapot.position.z=0.0;
	teapot.scale.x=1.0;
	teapot.scale.y=1.0;
	teapot.scale.z=1.0;
	teapot.rotate.x=0.;
	teapot.rotate.y=0.0;
	teapot.rotate.z=0.;

	teapot.ambient[0]=0.;
	teapot.ambient[1]=0.;
	teapot.ambient[2]=0.;
	teapot.ambient[3]=1.;
	teapot.diffuse[0]=0.1;
	teapot.diffuse[1]=0.5;
	teapot.diffuse[2]=0.8;
	teapot.diffuse[3]=1.;
	teapot.specular[0]=0.;
	teapot.specular[1]=0.;
	teapot.specular[2]=0.;
	teapot.specular[3]=1.;
	teapot.shininess=0.;
	teapot.emission[0]=0.;
	teapot.emission[1]=0.;
	teapot.emission[2]=0.;
	teapot.emission[3]=1.;

	teapot.display=glutSolidTeapot;
	teapot.display_selected=glutWireTeapot;


	//Show
	glutMainLoop ();
}

//Funcao de Desenho
void display(){
	//
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	//Desenha Objetos 3D
	obj3d_display(&sphere);
	obj3d_display(&cube);
	obj3d_display(&teapot);

	//Troca Buffers
	glutSwapBuffers();
}

//Listener do Tamanho da Janela
void reshape_listener (GLsizei w, GLsizei h) {
	// Para previnir uma divisão por zero
	if ( h == 0 ) h = 1;

	// Especifica o tamanho da viewport
	glViewport(0, 0, w, h);
	
	// Calcula a correção de aspecto
	cam_aspect((GLfloat)w/(GLfloat)h);
	
	//Reconfigura Camera
	cam_setup();
}

//Listener do Mouse
void mouse_listener(int button,int state,int x,int y){
}

//Listener do Scroll do Mouse
void mouse_wheel_listener(int wheel_number,int direction,int x,int y){
	cam_zoom(direction);
	cam_setup();
	glutPostRedisplay();
}

//Listener do Teclado
void key_listener(unsigned char key,int x,int y){
	if(selected==NULL){							//CAMERA
		switch(key){
			case GLUT_KEY_ESC:					//Sai do programa
				exit(0);
			case '8':							//Rotaciona para cima
				cam_rot_phi (-1);break;
			case '2':							//Rotaciona para baixo
				cam_rot_phi (1);break;
			case '4':							//Rotaciona para esquerda
				cam_rot_theta (-1);break;
			case '6':							//Rotaciona para direita
				cam_rot_theta (1);break;
			case '+':							//Afasta Camera
				cam_zoom(1);break;
			case '-':							//Aproxima Camera
				cam_zoom(-1);break;
		}
		//Reconfigura Camera
		cam_setup();
	}else{										//OBJETO
		switch(key){
			case GLUT_KEY_ESC:					//Desmarca objeto
				selected->selected=false;
				selected=NULL;
				break;
			case '8':							//Rotaciona para cima
				obj3d_rot_x(selected,-1);break;
			case '2':							//Rotaciona para baixo
				obj3d_rot_x(selected,1);break;
			case '4':							//Rotaciona para esquerda
				obj3d_rot_y(selected,-1);break;
			case '6':							//Rotaciona para direita
				obj3d_rot_y(selected,1);break;
			case '9':							//Rotaciona anti-horario
				obj3d_rot_z(selected,1);break;
			case '3':							//Rotaciona horario
				obj3d_rot_z(selected,-1);break;
			case '+':							//Aumenta Tamanho
				obj3d_size(selected,1);break;
			case '-':							// Reduz Tamanho
				obj3d_size(selected,-1);break;
			case 'q':							// Scala x +
				obj3d_scale_x(selected,1);break;
			case 'a':							// Scala x -
				obj3d_scale_x(selected,-1);break;
			case 'w':							// Scala y +
				obj3d_scale_y(selected,1);break;
			case 's':							// Scala y -
				obj3d_scale_y(selected,-1);break;
			case 'e':							// Scala z +
				obj3d_scale_z(selected,1);break;
			case 'd':							// Scala z -
				obj3d_scale_z(selected,-1);break;
		}
	}//ELSE

	//Redisplay
	glutPostRedisplay();
}

//Listener de Teclas Especiais
void special_key_listener(int key,int x,int y){
	if(selected==NULL){							//CAMERA
		switch(key){
			case GLUT_KEY_F1:					//Seleciona Chaleira
				selected=&teapot;
				selected->selected=true;
				break;
			case GLUT_KEY_F2:					//Seleciona Cubo
				selected=&cube;
				selected->selected=true;
				break;
			case GLUT_KEY_F3:					//Seleciona Esfera
				selected=&sphere;
				selected->selected=true;
				break;
			case GLUT_KEY_UP:					//Move a Camera para "Cima"
				cam_trans_y (1);break;
			case GLUT_KEY_DOWN:					//Move a Camera para "Baixo"
				cam_trans_y (-1);break;
			case GLUT_KEY_LEFT:					//Move a Camera para "Esquerda"
				cam_trans_x (-1);break;
			case GLUT_KEY_RIGHT:				//Move a Camera para "Direita"
				cam_trans_x (1);break;
			case GLUT_KEY_PAGE_UP:				//Move a Camera para "Tras"
				cam_trans_z (-1);break;
			case GLUT_KEY_PAGE_DOWN:			//Move a Camera para "Frente"
				cam_trans_z (1);break;
		}
		//Reconfigura Camera
		cam_setup();
	}else{										//OBJETO
		switch(key){
			case GLUT_KEY_F1:					//Sel. ou a Desmarca Cahaleira
				selected->selected=false;
				if (selected!=&teapot){
					selected=&teapot;
					selected->selected=true;
				}else
					selected=NULL;
				break;
			case GLUT_KEY_F2:					//Sel. ou a Desmarca Cubo
				selected->selected=false;
				if (selected!=&cube){
					selected=&cube;
					selected->selected=true;
				}else
					selected=NULL;
				break;
			case GLUT_KEY_F3:					//Sel. ou a Desmarca Esfera
				selected->selected=false;
				if (selected!=&sphere){
					selected=&sphere;
					selected->selected=true;
				}else
					selected=NULL;
				break;
			case GLUT_KEY_UP:					//Move o Objeto para "Cima"
				obj3d_trans_y(selected,1);break;
			case GLUT_KEY_DOWN:					//Move o Objeto para "Baixo"
				obj3d_trans_y(selected,-1);break;
			case GLUT_KEY_LEFT:					//Move o Objeto para "Esquerda"
				obj3d_trans_x(selected,-1);break;
			case GLUT_KEY_RIGHT:				//Move o Objeto para "Direita"
				obj3d_trans_x(selected,1);break;
			case GLUT_KEY_PAGE_UP:				//Move o Objeto para "Tras"
				obj3d_trans_z(selected,-1);break;
			case GLUT_KEY_PAGE_DOWN:			//Move o Objeto para "Frente"
				obj3d_trans_z(selected,1);break;
		}
	}
	//Redisplay
	glutPostRedisplay();
}

//Cria Menu
void create_menu(){
	//Submenu
	int obj_menu=glutCreateMenu(submenu_obj_listener);
	glutAddMenuEntry("None", 0);
	glutAddMenuEntry("Teapot", 1);
	glutAddMenuEntry("Cube", 2);
	glutAddMenuEntry("Sphere", 3);
	//Menu
	glutCreateMenu(menu_listener);
	glutAddSubMenu("Select Object", obj_menu);
	glutAddMenuEntry("Quit", 1);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
}

//Listener do Menu Principal
void menu_listener(int value){
	if(value==1)							//Finaliza Execucao
		exit(0);
}

//Listener do Submenu de Selecao de Objetos
void submenu_obj_listener(int value){
	if (selected!=NULL){					//Desmarca Objeto
		selected->selected=false;
		selected=NULL;
	}
	switch(value){
		case 1:								//Seleciona Chaleira
			selected=&teapot;
			selected->selected=true;
			break;
		case 2:								//Seleciona Cubo
			selected=&cube;
			selected->selected=true;
			break;
		case 3:								//Seleciona Esfera
			selected=&sphere;
			selected->selected=true;
			break;
	}
	//Redisplay
	glutPostRedisplay();
}


//Configura Luz
void setup_light(){
	GLfloat luzAmbiente[4]={0.2,0.2,0.2,1.0};		// luz ambiente
	GLfloat luzDifusa[4]={0.7,0.7,0.7,1.0};			// "cor" 
	GLfloat luzEspecular[4]={1.0, 1.0, 1.0, 1.0};   // "brilho" 
	GLfloat posicaoLuz[4]={100.0, 50.0, 50.0, 1.0}; // posicao da luz
	
	// Habilita o modelo de colorização de Gouraud
	glShadeModel(GL_SMOOTH);

	// Ativa o uso da luz ambiente 
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, luzAmbiente);

	// Define os parâmetros da luz de número 0
	glLightfv(GL_LIGHT0, GL_AMBIENT, luzAmbiente);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, luzDifusa );
	glLightfv(GL_LIGHT0, GL_SPECULAR, luzEspecular );
	glLightfv(GL_LIGHT0, GL_POSITION, posicaoLuz );

	// Habilita a definição da cor do material a partir da cor corrente
	glEnable(GL_COLOR_MATERIAL);
	//Habilita o uso de iluminação
	glEnable(GL_LIGHTING);
	// Habilita a luz de número 0
	glEnable(GL_LIGHT0);
	// Habilita o depth-buffering
	glEnable(GL_DEPTH_TEST);
}
